home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 23 / CU Amiga - Super CD-ROM 23 (June 1998).iso / CUCD / Games / ADoomPPC / src / amiga_net.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-06  |  36.0 KB  |  1,230 lines

  1.  
  2. #pragma options align=mac68k
  3.  
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <stdio.h>
  7. #include <time.h>
  8. #include <dos.h>
  9.  
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <arpa/inet.h>
  13. #include <errno.h>
  14. #include <unistd.h>
  15. #include <netdb.h>
  16. #include <sys/ioctl.h>
  17.  
  18. #include <exec/exec.h>
  19. #include <devices/serial.h>
  20. #include <proto/exec.h>
  21. #include <clib/socket_protos.h>
  22.  
  23. #ifdef AMIPX
  24. // These include file are distributed with amipx.library
  25. #include <amipx.h>
  26. #include <amipx_protos.h>
  27. #include <amipx_ppc_pragmas.h>
  28. #endif
  29.  
  30. #pragma options align=power
  31.  
  32. #include "i_system.h"
  33. #include "d_event.h"
  34. #include "d_net.h"
  35. #include "m_argv.h"
  36. #include "m_swap.h"
  37.  
  38. #include "doomstat.h"
  39.  
  40. #include "i_net.h"
  41.  
  42. extern struct ExecBase *SysBase;
  43.  
  44. #define    BeginIO(ioRequest)    _BeginIO(ioRequest)
  45.  
  46. extern void _BeginIO(struct IORequest *ioRequest);
  47.  
  48. extern void ppctimer (unsigned int *time);
  49. extern int bus_clock;
  50.  
  51. //
  52. // NETWORKING
  53. //
  54.  
  55. /**********************************************************************/
  56. /**********************************************************************/
  57. /* TCP/IP stuff */
  58.  
  59. struct Library *SocketBase = NULL;
  60.  
  61. static int IP_DOOMPORT = (IPPORT_USERRESERVED + 0x1d);
  62.  
  63. static int IP_sendsocket = -1;
  64. static int IP_insocket = -1;
  65.  
  66. static struct sockaddr_in IP_sendaddress[MAXNETNODES];
  67.  
  68. static void (*netget) (void);
  69. static void (*netsend) (void);
  70.  
  71.  
  72. /**********************************************************************/
  73. //
  74. // IP_UDPsocket
  75. //
  76. static int IP_UDPsocket (void)
  77. {
  78.   int s;
  79.  
  80.   // allocate a socket
  81.   s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  82.   if (s < 0)
  83.     I_Error ("can't create socket: %s", strerror(errno));
  84.   return s;
  85. }
  86.  
  87. /**********************************************************************/
  88. //
  89. // IP_BindToLocalPort
  90. //
  91. static void IP_BindToLocalPort (int s, int port)
  92. {
  93.   int v;
  94.   struct sockaddr_in address;
  95.  
  96.   memset (&address, 0, sizeof(address));
  97.   address.sin_family = AF_INET;
  98.   address.sin_addr.s_addr = INADDR_ANY;
  99.   address.sin_port = port;
  100.  
  101.   v = bind (s, (void *)&address, sizeof(address));
  102.   if (v == -1)
  103.     I_Error ("BindToPort: bind: %s", strerror(errno));
  104. }
  105.  
  106.  
  107. /**********************************************************************/
  108. //
  109. // IP_PacketSend
  110. //
  111. static void IP_PacketSend (void)
  112. {
  113.   int  c;
  114.   doomdata_t sw;
  115.  
  116.   // byte swap
  117.   sw.checksum = htonl(netbuffer->checksum);
  118.   sw.player = netbuffer->player;
  119.   sw.retransmitfrom = netbuffer->retransmitfrom;
  120.   sw.starttic = netbuffer->starttic;
  121.   sw.numtics = netbuffer->numtics;
  122.   for (c = 0 ; c < netbuffer->numtics; c++) {
  123.     sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
  124.     sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
  125.     sw.cmds[c].angleturn = htons(netbuffer->cmds[c].angleturn);
  126.     sw.cmds[c].consistancy = htons(netbuffer->cmds[c].consistancy);
  127.     sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
  128.     sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
  129.   }
  130.  
  131.   //printf ("sending %i\n",gametic);
  132.   c = sendto (IP_sendsocket , (UBYTE *)&sw, doomcom->datalength,
  133.               0, (void *)&IP_sendaddress[doomcom->remotenode],
  134.               sizeof(IP_sendaddress[doomcom->remotenode]));
  135. //  if (c == -1)
  136. //    /* why does AmiTCP 4.3 return EINVAL or ENOENT instead of EWOULDBLOCK ??? */
  137. //    if (errno != EWOULDBLOCK)
  138. //      I_Error ("SendPacket error: %s",strerror(errno));
  139. }
  140.  
  141.  
  142. /**********************************************************************/
  143. //
  144. // IP_PacketGet
  145. //
  146. static void IP_PacketGet (void)
  147. {
  148.   int i, c;
  149.   struct sockaddr_in fromaddress;
  150.   LONG fromlen;
  151.   doomdata_t sw;
  152.  
  153.   fromlen = sizeof(fromaddress);
  154.   c = recvfrom (IP_insocket, (UBYTE *)&sw, sizeof(sw), 0,
  155.                 (struct sockaddr *)&fromaddress, &fromlen);
  156.   if (c == -1) {
  157.     /* why does AmiTCP 4.3 return EINVAL or ENOENT instead of EWOULDBLOCK ??? */
  158. //    if (errno != EWOULDBLOCK)
  159. //      I_Error ("GetPacket: %s",strerror(errno));
  160.     doomcom->remotenode = -1;  // no packet
  161.     return;
  162.   }
  163.  
  164.   {
  165.     static int first=1;
  166.     if (first)
  167.       printf("len=%d:p=[0x%x 0x%x] \n", c, *(int*)&sw, *((int*)&sw+1));
  168.     first = 0;
  169.   }
  170.  
  171.   // find remote node number
  172.   for (i = 0; i < doomcom->numnodes; i++)
  173.     if (fromaddress.sin_addr.s_addr == IP_sendaddress[i].sin_addr.s_addr)
  174.       break;
  175.  
  176.   if (i == doomcom->numnodes) {
  177.     // packet is not from one of the players (new game broadcast)
  178.     doomcom->remotenode = -1;  // no packet
  179.     return;
  180.   }
  181.  
  182.   doomcom->remotenode = i;   // good packet from a game player
  183.   doomcom->datalength = c;
  184.  
  185.   // byte swap
  186.   netbuffer->checksum = ntohl(sw.checksum);
  187.   netbuffer->player = sw.player;
  188.   netbuffer->retransmitfrom = sw.retransmitfrom;
  189.   netbuffer->starttic = sw.starttic;
  190.   netbuffer->numtics = sw.numtics;
  191.  
  192.   for (c = 0; c < netbuffer->numtics; c++) {
  193.     netbuffer->cmds[c].forwardmove = sw.cmds[c].forwardmove;
  194.     netbuffer->cmds[c].sidemove = sw.cmds[c].sidemove;
  195.     netbuffer->cmds[c].angleturn = ntohs(sw.cmds[c].angleturn);
  196.     netbuffer->cmds[c].consistancy = ntohs(sw.cmds[c].consistancy);
  197.     netbuffer->cmds[c].chatchar = sw.cmds[c].chatchar;
  198.     netbuffer->cmds[c].buttons = sw.cmds[c].buttons;
  199.   }
  200. }
  201.  
  202.  
  203. /**********************************************************************/
  204. #if 0
  205. static int IP_GetLocalAddress (void)
  206. {
  207.   char hostname[1024];
  208.   struct hostent* hostentry; // host information entry
  209.   int v;
  210.  
  211.   // get local address
  212.   v = gethostname (hostname, sizeof(hostname));
  213.   if (v == -1)
  214.     I_Error ("IP_GetLocalAddress : gethostname: errno %d",errno);
  215.  
  216.   hostentry = gethostbyname (hostname);
  217.   if (!hostentry)
  218.     I_Error ("IP_GetLocalAddress : gethostbyname: couldn't get local host");
  219.  
  220.   return *(int *)hostentry->h_addr_list[0];
  221. }
  222. #endif
  223.  
  224. /**********************************************************************/
  225. //
  226. // IP_InitNetwork
  227. //
  228. static void IP_InitNetwork (int i)
  229. {
  230.   char trueval = true;
  231.   struct hostent* hostentry; // host information entry
  232.  
  233.   if ((SocketBase = OpenLibrary ("bsdsocket.library", 0)) == NULL)
  234.     I_Error ("OpenLibrary(\"bsdsocket.library\") failed");
  235.  
  236.   netsend = IP_PacketSend;
  237.   netget = IP_PacketGet;
  238.   netgame = true;
  239.  
  240.   // parse player number and host list
  241.   doomcom->consoleplayer = myargv[i+1][0]-'1';
  242.  
  243.   doomcom->numnodes = 1; // this node for sure
  244.  
  245.   i++;
  246.   while (++i < myargc && myargv[i][0] != '-') {
  247.     IP_sendaddress[doomcom->numnodes].sin_family = AF_INET;
  248.     IP_sendaddress[doomcom->numnodes].sin_port = htons(IP_DOOMPORT);
  249.     if (myargv[i][0] == '.') {
  250.       IP_sendaddress[doomcom->numnodes].sin_addr.s_addr = inet_addr (myargv[i]+1);
  251.     } else {
  252.       hostentry = gethostbyname (myargv[i]);
  253.       if (!hostentry)
  254.         I_Error ("gethostbyname: couldn't find %s", myargv[i]);
  255.       IP_sendaddress[doomcom->numnodes].sin_addr.s_addr =
  256.                                               *(int *)hostentry->h_addr_list[0];
  257.     }
  258.     doomcom->numnodes++;
  259.   }
  260.  
  261.   doomcom->id = DOOMCOM_ID;
  262.   doomcom->numplayers = doomcom->numnodes;
  263.  
  264.   // build message to receive
  265.   IP_insocket = IP_UDPsocket ();
  266.   IP_sendsocket = IP_UDPsocket ();
  267.  
  268.   IP_BindToLocalPort (IP_insocket, htons(IP_DOOMPORT));
  269.  
  270.   /* set both sockets to non-blocking */
  271.   if (IoctlSocket (IP_insocket, FIONBIO, &trueval) == -1 ||
  272.       IoctlSocket (IP_sendsocket, FIONBIO, &trueval) == -1)
  273.     I_Error ("IoctlSocket() failed: %s", strerror(errno));
  274. }
  275.  
  276. /**********************************************************************/
  277. static void IP_Shutdown (void)
  278. {
  279.   if (IP_insocket != -1) {
  280.     CloseSocket (IP_insocket);
  281.     IP_insocket = -1;
  282.   }
  283.   if (IP_sendsocket != -1) {
  284.     CloseSocket (IP_sendsocket);
  285.     IP_sendsocket = -1;
  286.   }
  287.   if (SocketBase != NULL) {
  288.     CloseLibrary (SocketBase);
  289.     SocketBase = NULL;
  290.   }
  291. }
  292.  
  293. /**********************************************************************/
  294. /**********************************************************************/
  295. /* experimental low level serial port stuff */
  296.  
  297. static struct MsgPort *SER_writelen_mp = NULL;
  298. static struct MsgPort *SER_readlen_mp = NULL;
  299. static struct MsgPort *SER_write_mp = NULL;
  300. static struct MsgPort *SER_read_mp = NULL;
  301. static struct IOExtSer *SER_writelen_io = NULL;
  302. static struct IOExtSer *SER_readlen_io = NULL;
  303. static struct IOExtSer *SER_write_io = NULL;
  304. static struct IOExtSer *SER_read_io = NULL;
  305. static BOOL SER_is_open = FALSE;
  306. static BOOL SER_write_in_progress = FALSE;
  307. static BOOL SER_read_in_progress = FALSE;
  308. static BOOL SER_readlen_in_progress = FALSE;
  309. static BOOL SER_read_waiting_for_len;
  310. static UBYTE SER_get_len, SER_get_len2;
  311. static doomdata_t SER_get_sw;
  312.  
  313. /**********************************************************************/
  314. //
  315. // SER_PacketSend
  316. //
  317. static void SER_PacketSend (void)
  318. {
  319.   int  c;
  320.   static doomdata_t sw;
  321.   static UBYTE len;
  322.  
  323.   if (SER_write_in_progress) {
  324.  
  325. //    if (!CheckIO ((struct IORequest *)SER_write_io))
  326. //      return;       /* previous write hasn't finished yet, forget it */
  327.  
  328.     WaitIO ((struct IORequest *)SER_writelen_io);
  329.     WaitIO ((struct IORequest *)SER_write_io);
  330.     SER_write_in_progress = FALSE;
  331.   }
  332.  
  333.   // byte swap
  334.   sw.checksum = htonl(netbuffer->checksum);
  335.   sw.player = netbuffer->player;
  336.   sw.retransmitfrom = netbuffer->retransmitfrom;
  337.   sw.starttic = netbuffer->starttic;
  338.   sw.numtics = netbuffer->numtics;
  339.   for (c = 0 ; c < netbuffer->numtics; c++) {
  340.     sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
  341.     sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
  342.     sw.cmds[c].angleturn = htons(netbuffer->cmds[c].angleturn);
  343.     sw.cmds[c].consistancy = htons(netbuffer->cmds[c].consistancy);
  344.     sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
  345.     sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
  346.   }
  347.  
  348.   len = doomcom->datalength;
  349.  
  350.   if (len > 0) {
  351.  
  352. //    printf ("Sending len = %d  %08x %08x ...\n", len, ((ULONG *)&sw)[0],
  353. //            ((ULONG *)&sw)[1]);
  354.  
  355.     SER_writelen_io->IOSer.io_Length = 1;
  356.     SER_writelen_io->IOSer.io_Data = &len;
  357.     SER_writelen_io->IOSer.io_Command = CMD_WRITE;
  358.     SER_writelen_io->IOSer.io_Flags |= IOF_QUICK;
  359.     BeginIO ((struct IORequest *)SER_writelen_io);
  360.  
  361.     SER_write_io->IOSer.io_Length = len;
  362.     SER_write_io->IOSer.io_Data = (UBYTE *)&sw;
  363.     SER_write_io->IOSer.io_Command = CMD_WRITE;
  364.     SER_write_io->IOSer.io_Flags |= IOF_QUICK;
  365.     BeginIO ((struct IORequest *)SER_write_io);
  366.  
  367.     SER_write_in_progress = TRUE;
  368.  
  369.   }
  370. }
  371.  
  372. /**********************************************************************/
  373. //
  374. // SER_PacketGet
  375. //
  376. static void SER_PacketGet (void)
  377. {
  378.   int c;
  379.  
  380.   if (SER_read_waiting_for_len) {
  381.  
  382.     if (!CheckIO ((struct IORequest *)SER_readlen_io)) {
  383.       doomcom->remotenode = -1;  // no packet
  384.       return;
  385.     }
  386.  
  387.     WaitIO ((struct IORequest *)SER_readlen_io);/* should return immediately */
  388.     SER_readlen_in_progress = FALSE;
  389.  
  390.     SER_get_len2 = SER_get_len;
  391.  
  392.     if (SER_get_len2 != 0) {
  393.  
  394. //      printf ("Receiving len = %d, lenstatus = %d", (int)SER_get_len2,
  395. //              SER_readlen_io->IOSer.io_Error);
  396.  
  397.       SER_read_io->IOSer.io_Length = SER_get_len2;
  398.       SER_read_io->IOSer.io_Data = (UBYTE *)&SER_get_sw;
  399.       SER_read_io->IOSer.io_Command = CMD_READ;
  400.       SER_read_io->IOSer.io_Flags |= IOF_QUICK;
  401.       BeginIO ((struct IORequest *)SER_read_io);
  402.       SER_read_in_progress = TRUE;
  403.  
  404.       SER_read_waiting_for_len = FALSE;
  405.  
  406.     }
  407.     SER_readlen_io->IOSer.io_Length = 1;
  408.     SER_readlen_io->IOSer.io_Data = &SER_get_len;
  409.     SER_readlen_io->IOSer.io_Command = CMD_READ;
  410.     SER_readlen_io->IOSer.io_Flags |= IOF_QUICK;
  411.     BeginIO ((struct IORequest *)SER_readlen_io);
  412.     SER_readlen_in_progress = TRUE;
  413.  
  414.     doomcom->remotenode = -1;  // no packet
  415.     return;
  416.   }
  417.  
  418.   if (SER_read_in_progress)
  419.     if (!CheckIO ((struct IORequest *)SER_read_io)) {
  420.       doomcom->remotenode = -1;  // no packet
  421.       return;
  422.     }
  423.  
  424.   WaitIO ((struct IORequest *)SER_read_io); /* should return immediately */
  425.   SER_read_in_progress = FALSE;
  426.  
  427. //  printf (", status = %d  %08x %08x ...\n", SER_read_io->IOSer.io_Error,
  428. //          ((ULONG *)&SER_get_sw)[0], ((ULONG *)&SER_get_sw)[1]);
  429.  
  430.   {
  431.     static int first=1;
  432.     if (first)
  433.       printf("len=%d:p=[0x%x 0x%x] \n", SER_get_len2, *(int*)&SER_get_sw,
  434.              *((int*)&SER_get_sw+1));
  435.     first = 0;
  436.   }
  437.  
  438.   doomcom->remotenode = 1;  /* from the other player */
  439.   doomcom->datalength = SER_get_len2;
  440.  
  441.   // byte swap
  442.   netbuffer->checksum = ntohl(SER_get_sw.checksum);
  443.   netbuffer->player = SER_get_sw.player;
  444.   netbuffer->retransmitfrom = SER_get_sw.retransmitfrom;
  445.   netbuffer->starttic = SER_get_sw.starttic;
  446.   netbuffer->numtics = SER_get_sw.numtics;
  447.  
  448.   for (c = 0; c < netbuffer->numtics; c++) {
  449.     netbuffer->cmds[c].forwardmove = SER_get_sw.cmds[c].forwardmove;
  450.     netbuffer->cmds[c].sidemove = SER_get_sw.cmds[c].sidemove;
  451.     netbuffer->cmds[c].angleturn = ntohs(SER_get_sw.cmds[c].angleturn);
  452.     netbuffer->cmds[c].consistancy = ntohs(SER_get_sw.cmds[c].consistancy);
  453.     netbuffer->cmds[c].chatchar = SER_get_sw.cmds[c].chatchar;
  454.     netbuffer->cmds[c].buttons = SER_get_sw.cmds[c].buttons;
  455.   }
  456.  
  457.   SER_read_waiting_for_len = TRUE;
  458. }
  459.  
  460. /**********************************************************************/
  461. //
  462. // SER_InitNetwork
  463. //
  464. void SER_InitNetwork (int i)
  465. {
  466.   int unit, speed;
  467.  
  468.   netsend = SER_PacketSend;
  469.   netget = SER_PacketGet;
  470.   netgame = true;
  471.  
  472.   // parse player number and host list
  473.   doomcom->consoleplayer = myargv[i+1][0]-'1';
  474.  
  475.   doomcom->numnodes = 2;
  476.   doomcom->id = DOOMCOM_ID;
  477.   doomcom->numplayers = doomcom->numnodes;
  478.  
  479.   if ((SER_writelen_mp = CreatePort (NULL, 0)) == NULL ||
  480.       (SER_readlen_mp = CreatePort (NULL, 0)) == NULL ||
  481.       (SER_write_mp = CreatePort (NULL, 0)) == NULL ||
  482.       (SER_read_mp = CreatePort (NULL, 0)) == NULL ||
  483.       (SER_writelen_io = (struct IOExtSer *)CreateExtIO (SER_writelen_mp,
  484.                                             sizeof(struct IOExtSer))) == NULL ||
  485.       (SER_readlen_io = (struct IOExtSer *)CreateExtIO (SER_readlen_mp,
  486.                                             sizeof(struct IOExtSer))) == NULL ||
  487.       (SER_write_io = (struct IOExtSer *)CreateExtIO (SER_write_mp,
  488.                                             sizeof(struct IOExtSer))) == NULL ||
  489.       (SER_read_io = (struct IOExtSer *)CreateExtIO (SER_read_mp,
  490.                                             sizeof(struct IOExtSer))) == NULL)
  491.     I_Error ("Can't create port");
  492.  
  493.   unit = atoi(myargv[i+3]);
  494.   speed = atoi(myargv[i+4]);
  495.  
  496.   SER_write_io->io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
  497.  
  498.   if (OpenDevice (myargv[i+2], unit, (struct IORequest *)SER_write_io, 0) != 0)
  499.     I_Error ("Can't open %s port %d", myargv[i+2], unit);
  500.   SER_is_open = TRUE;
  501.  
  502.   SER_write_io->io_SerFlags &= ~SERF_PARTY_ON;
  503.   SER_write_io->io_SerFlags |= SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
  504.   SER_write_io->io_Baud = speed;
  505.   SER_write_io->io_ReadLen = 8;
  506.   SER_write_io->io_WriteLen = 8;
  507.   SER_write_io->io_StopBits = 1;
  508.   SER_write_io->io_RBufLen = 65536;
  509.   SER_write_io->IOSer.io_Command = SDCMD_SETPARAMS;
  510.   if (DoIO ((struct IORequest *)SER_write_io) != 0)
  511.     I_Error ("Error setting serial parameters (speed = %d)", speed);
  512.  
  513.   CopyMem (SER_write_io, SER_read_io, sizeof(struct IOExtSer));
  514.   SER_read_io->IOSer.io_Message.mn_ReplyPort = SER_read_mp;
  515.  
  516.   CopyMem (SER_write_io, SER_readlen_io, sizeof(struct IOExtSer));
  517.   SER_readlen_io->IOSer.io_Message.mn_ReplyPort = SER_readlen_mp;
  518.  
  519.   CopyMem (SER_write_io, SER_writelen_io, sizeof(struct IOExtSer));
  520.   SER_writelen_io->IOSer.io_Message.mn_ReplyPort = SER_writelen_mp;
  521.  
  522.   SER_readlen_io->IOSer.io_Length = 1;
  523.   SER_readlen_io->IOSer.io_Data = &SER_get_len;
  524.   SER_readlen_io->IOSer.io_Command = CMD_READ;
  525.   SER_readlen_io->IOSer.io_Flags |= IOF_QUICK;
  526.   BeginIO ((struct IORequest *)SER_readlen_io);
  527.   SER_readlen_in_progress = TRUE;
  528.  
  529.   SER_read_waiting_for_len = TRUE;
  530.  
  531. }
  532.  
  533. /**********************************************************************/
  534. static void SER_Shutdown (void)
  535. {
  536.   if (SER_is_open) {
  537.     if (SER_readlen_in_progress) {
  538.       AbortIO ((struct IORequest *)SER_readlen_io);
  539.       WaitIO ((struct IORequest *)SER_readlen_io);
  540.       SER_readlen_in_progress = FALSE;
  541.     }
  542.     if (SER_read_in_progress) {
  543.       AbortIO ((struct IORequest *)SER_read_io);
  544.       WaitIO ((struct IORequest *)SER_read_io);
  545.       SER_read_in_progress = FALSE;
  546.     }
  547.     if (SER_write_in_progress) {
  548.       AbortIO ((struct IORequest *)SER_writelen_io);
  549.       WaitIO ((struct IORequest *)SER_writelen_io);
  550.       AbortIO ((struct IORequest *)SER_write_io);
  551.       WaitIO ((struct IORequest *)SER_write_io);
  552.       SER_write_in_progress = FALSE;
  553.     }
  554.     CloseDevice ((struct IORequest *)SER_write_io);
  555.     SER_is_open = FALSE;
  556.   }
  557.   if (SER_readlen_io != NULL) {
  558.     DeleteExtIO ((struct IORequest *)SER_readlen_io);
  559.     SER_readlen_io = NULL;
  560.   }
  561.   if (SER_readlen_mp != NULL) {
  562.     DeletePort (SER_readlen_mp);
  563.     SER_readlen_mp = NULL;
  564.   }
  565.   if (SER_writelen_io != NULL) {
  566.     DeleteExtIO ((struct IORequest *)SER_writelen_io);
  567.     SER_writelen_io = NULL;
  568.   }
  569.   if (SER_writelen_mp != NULL) {
  570.     DeletePort (SER_writelen_mp);
  571.     SER_writelen_mp = NULL;
  572.   }
  573.   if (SER_read_io != NULL) {
  574.     DeleteExtIO ((struct IORequest *)SER_read_io);
  575.     SER_read_io = NULL;
  576.   }
  577.   if (SER_read_mp != NULL) {
  578.     DeletePort (SER_read_mp);
  579.     SER_read_mp = NULL;
  580.   }
  581.   if (SER_write_io != NULL) {
  582.     DeleteExtIO ((struct IORequest *)SER_write_io);
  583.     SER_write_io = NULL;
  584.   }
  585.   if (SER_write_mp != NULL) {
  586.     DeletePort (SER_write_mp);
  587.     SER_write_mp = NULL;
  588.   }
  589. }
  590.  
  591. /**********************************************************************/
  592. /**********************************************************************/
  593.  
  594. #ifdef AMIPX
  595.  
  596. /**********************************************************************/
  597. /* experimental IPX stuff */
  598.  
  599. #define IPX_NUMPACKETS      10          // max outstanding packets before loss
  600.  
  601. #pragma options align=mac68k
  602.  
  603. // setupdata_t is used as doomdata_t during setup
  604. typedef struct
  605. {
  606.   WORD gameid;      // so multiple games can setup at once
  607.   WORD drone;       // You must take care to make gameid LSB first - GJP
  608.   WORD nodesfound;  // these two are only compared to each other so it
  609.   WORD nodeswanted; // does not matter what internal storage you use
  610. } setupdata_t;
  611.  
  612. typedef struct {
  613.   UBYTE network[4];             /* high-low */
  614.   UBYTE node[6];                /* high-low */
  615. } localadr_t;
  616.  
  617. typedef struct {
  618.   UBYTE node[6];                /* high-low */
  619. } nodeadr_t;
  620.  
  621. // I think a version I downloaded in late 1997, used just one fragment,
  622. // but multiple fragments is supported by AMIPX, I even endorse it - GJP 
  623.  
  624. // time is used by the communication driver to sequence packets returned
  625. // to DOOM when more than one is waiting
  626. // this is were the 68k has to be very careful to store the time LSB first- GJP
  627.  
  628. typedef struct {
  629.   struct AMIPX_ECB ecb;      /* too small!!!  need space for 2 fragments !!! */
  630.   struct AMIPX_Fragment dummy;  /* maybe this will fix it */
  631.   struct AMIPX_PacketHeader ipx;
  632.   long time;
  633.   doomdata_t data;
  634. } packet_t;
  635.  
  636. #pragma options align=power
  637.  
  638. struct AMIPX_Library *AMIPX_Library = NULL;
  639. static packet_t IPX_packets[IPX_NUMPACKETS];
  640. static nodeadr_t IPX_nodeadr[MAXNETNODES+1];  // first is local, last is broadcast
  641. static nodeadr_t IPX_remoteadr;               // set by each GetPacket
  642. static localadr_t IPX_localadr;        // set at startup
  643. static UWORD IPX_socketid = 0;
  644. static long IPX_localtime;          // for time stamp in packets
  645. static long IPX_remotetime;
  646. static BOOL IPX_got_a_packet;
  647.  
  648. /**********************************************************************/
  649. static int IPX_OpenSocket (WORD socketNumber)
  650. {
  651.   int outsock;
  652.  
  653.   if ((outsock = AMIPX_OpenSocket (socketNumber)) == 0)
  654.     I_Error ("AMIPX_OpenSocket() failed");
  655.   return outsock;
  656. }
  657.  
  658. /**********************************************************************/
  659. static void IPX_ListenForPacket (struct AMIPX_ECB *ecb)
  660. {
  661.   int retval;
  662.  
  663.   if ((retval = AMIPX_ListenForPacket (ecb)))
  664.     I_Error ("ListenForPacket: 0x%x", retval);
  665. }
  666.  
  667. /**********************************************************************/
  668.  
  669. #if 0
  670.  
  671. static void print_address (char *msg, struct AMIPX_Address *adr)
  672. {
  673.   printf ("   %s Network:         %02x:%02x:%02x:%02x\n", msg,
  674.           adr->Network[0], adr->Network[1],
  675.           adr->Network[2], adr->Network[3]);
  676.   printf ("   %s Node:            %02x:%02x:%02x:%02x:%02x:%02x\n", msg,
  677.           adr->Node[0], adr->Node[1], adr->Node[2],
  678.           adr->Node[3], adr->Node[4], adr->Node[5]);
  679.   printf ("   %s Socket:          %04x\n", msg, adr->Socket);
  680. }
  681.  
  682. /**********************************************************************/
  683. static void print_ipx (struct AMIPX_PacketHeader *ipx)
  684. {
  685.   printf ("IPX Packet header at $%08x\n", ipx);
  686.   printf ("  Checksum:             %04x\n", ipx->Checksum);
  687.   printf ("  Length:               %04x\n", ipx->Length);
  688.   printf ("  Tc:                   %02x\n", ipx->Tc);
  689.   printf ("  Type:                 %02x\n", ipx->Type);
  690.   print_address ("Dst", &ipx->Dst);
  691.   print_address ("Src", &ipx->Src);
  692. }
  693.  
  694. /**********************************************************************/
  695. static void print_ecb (struct AMIPX_ECB *ecb)
  696. {
  697.   int i;
  698.  
  699.   printf ("ECB   at $%08x\n", ecb);
  700.   printf ("  Link:                 %08x\n", ecb->Link);
  701.   printf ("  ESR:                  %08x\n", ecb->ESR);
  702.   printf ("  InUse:                %02x\n", ecb->InUse);
  703.   printf ("  CompletionCode:       %02x\n", ecb->CompletionCode);
  704.   printf ("  Socket:               %04x\n", ecb->Socket);
  705.   printf ("  IPXWork:              %02x:%02x:%02x:%02x\n",
  706.           ecb->IPXWork[0], ecb->IPXWork[1],
  707.           ecb->IPXWork[2], ecb->IPXWork[3]);
  708.   printf ("  ImmedAddr:            %02x:%02x:%02x:%02x:%02x:%02x\n",
  709.           ecb->ImmedAddr[0], ecb->ImmedAddr[1],
  710.           ecb->ImmedAddr[2], ecb->ImmedAddr[3],
  711.           ecb->ImmedAddr[4], ecb->ImmedAddr[5]);
  712.   printf ("  FragCount:            %04x\n", ecb->FragCount);
  713.   for (i = 0; i < ecb->FragCount; i++) {
  714.     printf ("  Fragment[%d].FragData: %08x\n", i, ecb->Fragment[i].FragData);
  715.     printf ("  Fragment[%d].FragSize: %04x\n", i,
  716.             ecb->Fragment[i].FragSize);
  717.   }
  718. }
  719.  
  720. #endif
  721.  
  722. /**********************************************************************/
  723. // Send the data defined by doomcom->data and doomcom->datalength
  724. // to the node doomcom->remotenode.
  725. // Broadcast if doomcom->remotenode == MAXNETNODES
  726.  
  727. static void IPX_PacketSend (void)
  728. {
  729.   int j, c, retval;
  730.   int destination;
  731.   int len;
  732.   doomdata_t sw;
  733.  
  734.   // byte swap if not in setup
  735.   if (IPX_localtime != -1) {
  736.     sw.checksum = SWAPLONG(netbuffer->checksum);
  737.     sw.player = netbuffer->player;
  738.     sw.retransmitfrom = netbuffer->retransmitfrom;
  739.     sw.starttic = netbuffer->starttic;
  740.     sw.numtics = netbuffer->numtics;
  741.  
  742.     for (c = 0 ; c < netbuffer->numtics; c++) {
  743.       sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
  744.       sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
  745.       sw.cmds[c].angleturn = SWAPSHORT(netbuffer->cmds[c].angleturn);
  746.       sw.cmds[c].consistancy = SWAPSHORT(netbuffer->cmds[c].consistancy);
  747.       sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
  748.       sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
  749.     }
  750.     IPX_packets[0].ecb.Fragment[1].FragData = (UBYTE *)&sw;
  751.   } else
  752.     IPX_packets[0].ecb.Fragment[1].FragData = (UBYTE *)&doomcom->data;
  753.  
  754.   destination = doomcom->remotenode;
  755.  
  756. // set the time
  757.   IPX_packets[0].time = SWAPLONG(IPX_localtime); // Amiga puts MSB first
  758.  
  759. // set the address
  760.   for (j = 0; j < 6; j++)
  761.     IPX_packets[0].ipx.Dst.Node[j] = IPX_packets[0].ecb.ImmedAddr[j]
  762.                                    = IPX_nodeadr[destination].node[j];
  763.  
  764. // set the length (ipx + time + datalength)
  765.   len = sizeof(struct AMIPX_PacketHeader) + sizeof(long) + doomcom->datalength
  766.         + 4;
  767.   IPX_packets[0].ipx.Checksum = 0xffff;
  768.   IPX_packets[0].ipx.Length = len;
  769.   IPX_packets[0].ipx.Type = 4;
  770.   IPX_packets[0].ecb.Fragment[0].FragSize = sizeof(struct AMIPX_PacketHeader)
  771.                                             + sizeof(long);
  772.   IPX_packets[0].ecb.Fragment[1].FragSize = doomcom->datalength + 4;
  773.  
  774. // send the packet
  775. /*
  776.   printf ("Sending ");
  777.   print_ecb (&(IPX_packets[0].ecb));
  778.   printf ("with IPX header ");
  779.   print_ipx ((struct AMIPX_PacketHeader *)
  780.              IPX_packets[0].ecb.Fragment[0].FragData);
  781. */
  782.   if ((retval = AMIPX_SendPacket (&(IPX_packets[0].ecb))) != 0)
  783.     I_Error ("SendPacket: 0x%x", retval);
  784.  
  785.   while(IPX_packets[0].ecb.InUse != 0) {
  786. // IPX Relinquish Control - polled drivers MUST have this here!
  787.     AMIPX_RelinquishControl ();
  788.   }
  789. }
  790.  
  791. /**********************************************************************/
  792. // If there are no packets to receive, set IPX_got_a_packet = FALSE,
  793. //   and doomcom->remotenode = -1.
  794. // Otherwise set IPX_got_a_packet to TRUE and return packet in
  795. //   doomcom->data and doomcom->datalen.
  796. // Set IPX_remoteadr to address of remote node.
  797. // If we know who it came from, set doomcom->remotenode accordingly,
  798. //   otherwise set doomcom->remotenode = -1.
  799.  
  800. static void IPX_PacketGet (void)
  801. {
  802.   int packetnum;
  803.   int i, c;
  804.   long besttic;
  805.   packet_t *packet;
  806.   doomdata_t *sw;
  807.  
  808. // if multiple packets are waiting, return them in order by time
  809.  
  810.   IPX_got_a_packet = FALSE;
  811.   besttic = MAXLONG;
  812.   packetnum = -1;
  813.   doomcom->remotenode = -1;
  814.  
  815.   /* printf ("Looking for received packets...\n"); */
  816.  
  817.   for (i = 1; i < IPX_NUMPACKETS; i++)
  818.     if (!IPX_packets[i].ecb.InUse) {
  819.  
  820.       /* printf ("\nGOT A PACKET!!!\n"); */
  821.  
  822.       if ((IPX_localtime != -1 && IPX_packets[i].time == -1))
  823.         IPX_ListenForPacket (&IPX_packets[i].ecb); // unwanted packet
  824.       else if (SWAPLONG(IPX_packets[i].time) < besttic) {
  825.         besttic = SWAPLONG(IPX_packets[i].time);
  826.         packetnum = i;
  827.       }
  828.     }
  829.  
  830.   if (besttic == MAXLONG)
  831.     return;                           // no packets
  832.  
  833. //
  834. // got a good packet
  835. //
  836.   IPX_got_a_packet = TRUE;
  837.   packet = &IPX_packets[packetnum];
  838.   IPX_remotetime = besttic;
  839.  
  840.   if (packet->ecb.CompletionCode)
  841.     I_Error ("IPX_PacketGet: ecb.CompletionCode = 0x%x",
  842.              packet->ecb.CompletionCode);
  843. // corrected that ancient typo, sorry - GJP
  844. // set IPX_remoteadr to the sender of the packet
  845.   memcpy (&IPX_remoteadr, packet->ipx.Src.Node, sizeof(IPX_remoteadr));
  846.   for (i = 0; i < doomcom->numnodes; i++)
  847.     if (!memcmp(&IPX_remoteadr, &IPX_nodeadr[i], sizeof(IPX_remoteadr)))
  848.       break;
  849.   if (i < doomcom->numnodes)
  850.     doomcom->remotenode = i;
  851.   else {
  852.     if (IPX_localtime != -1) {    // this really shouldn't happen
  853.       IPX_ListenForPacket (&packet->ecb);
  854.       return;
  855.     }
  856.   }
  857.  
  858. // copy out the data
  859.   doomcom->datalength = packet->ipx.Length - sizeof(struct AMIPX_PacketHeader)
  860.                         - sizeof(long) - 4;
  861.   // byte swap if not in setup time
  862.   if (IPX_localtime != -1) {
  863.     sw = &packet->data;
  864.     netbuffer->checksum = SWAPLONG(sw->checksum);
  865.     netbuffer->player = sw->player;
  866.     netbuffer->retransmitfrom = sw->retransmitfrom;
  867.     netbuffer->starttic = sw->starttic;
  868.     netbuffer->numtics = sw->numtics;
  869.  
  870.     for (c = 0; c < netbuffer->numtics; c++) {
  871.       netbuffer->cmds[c].forwardmove = sw->cmds[c].forwardmove;
  872.       netbuffer->cmds[c].sidemove = sw->cmds[c].sidemove;
  873.       netbuffer->cmds[c].angleturn = SWAPSHORT(sw->cmds[c].angleturn);
  874.       netbuffer->cmds[c].consistancy = SWAPSHORT(sw->cmds[c].consistancy);
  875.       netbuffer->cmds[c].chatchar = sw->cmds[c].chatchar;
  876.       netbuffer->cmds[c].buttons = sw->cmds[c].buttons;
  877.     }
  878.   } else
  879.     memcpy (&doomcom->data, &packet->data, doomcom->datalength);
  880.  
  881. // repost the ECB
  882.   IPX_ListenForPacket (&packet->ecb);
  883. }
  884.  
  885. /**********************************************************************/
  886. static void IPX_LookForNodes (int numnetnodes)
  887. {
  888.   int i;
  889.   unsigned int clock[2];
  890.   int oldsec;
  891.   int currsec;
  892.   setupdata_t *dest;
  893.   int total, console;
  894.   static setupdata_t nodesetup[MAXNETNODES];
  895.  
  896. //
  897. // wait until we get [numnetnodes] packets, then start playing
  898. // the playernumbers are assigned by netid
  899. //
  900.   printf ("Attempting to find all players for %i player net play. "
  901.           "Press CTRL/C to exit.\n", numnetnodes);
  902.  
  903.   printf ("Looking for a node...\n");
  904.  
  905.   oldsec = -1;
  906.   IPX_localtime = -1;          // in setup time, not game time
  907.  
  908. //
  909. // build local setup info
  910. //
  911.   nodesetup[0].nodesfound = 1;
  912.   nodesetup[0].nodeswanted = numnetnodes;
  913.   doomcom->numnodes = 1;
  914.  
  915.   for (;;) {
  916.     //
  917.     // check for aborting
  918.     //
  919.     chkabort ();
  920.  
  921.     //
  922.     // listen to the network
  923.     //
  924.     for (;;) {
  925.  
  926.       IPX_PacketGet ();
  927.  
  928.       if (!IPX_got_a_packet)
  929.         break;
  930.  
  931.       if (doomcom->remotenode == -1) {     // it's from a new address
  932.         dest = &nodesetup[doomcom->numnodes];
  933.       } else {                        // it's from a node we already know about
  934.         dest = &nodesetup[doomcom->remotenode];
  935.       }
  936.  
  937.       if (IPX_remotetime != -1) {   // an early game packet, not a setup packet
  938.         if (doomcom->remotenode == -1)
  939.           I_Error ("Got an unknown game packet during setup");
  940.         // if it allready started, it must have found all nodes
  941.         dest->nodesfound = dest->nodeswanted;  // both swapped
  942.         continue;
  943.       }
  944.  
  945.       // update setup info
  946.       memcpy (dest, &doomcom->data, sizeof(*dest));
  947.  
  948.       if (doomcom->remotenode == -1) {     // it's from a new address
  949.  
  950.         memcpy (&IPX_nodeadr[doomcom->numnodes], &IPX_remoteadr,
  951.                 sizeof(IPX_nodeadr[doomcom->numnodes]));
  952.         //
  953.         // if this node has a lower address, take all startup info
  954.         //
  955.         if (memcmp(&IPX_remoteadr, &IPX_nodeadr[0], sizeof(&IPX_remoteadr))
  956.                                                                          < 0) {
  957.         }  // No action ?!
  958.            // You could call this a bug - how does one DOOM know
  959.            // whether everyone wants the same number of players?
  960.            // However, because of this, using internal storage for
  961.            // these setup packets actually works.
  962.            // (which saves the Mac version, because if this was not
  963.            // ignored, the PC would start looking for a multiple of
  964.            // 256 players) - GJP
  965.  
  966.         doomcom->numnodes++;
  967.  
  968.         printf ("\nFound node [%02x:%02x:%02x:%02x:%02x:%02x]\n",
  969.                 IPX_remoteadr.node[0], IPX_remoteadr.node[1],
  970.                 IPX_remoteadr.node[2], IPX_remoteadr.node[3],
  971.                 IPX_remoteadr.node[4], IPX_remoteadr.node[5]);
  972.  
  973.         if (doomcom->numnodes < numnetnodes)
  974.           printf ("Looking for a node...\n");
  975.  
  976.       } /* end if (doomcom->remotenode == -1) */
  977.  
  978.     } /* end for (;;) until no more packets received */
  979.  
  980.     //
  981.     // we are done if all nodes have found all other nodes
  982.     //
  983.     for (i = 0; i < doomcom->numnodes; i++)
  984.       if (nodesetup[i].nodesfound != nodesetup[i].nodeswanted) // both swapped
  985.         break;
  986.  
  987.     // You will notice that nodesetup[0].nodesfound is never compared to
  988.     // nodesetup[i].nodeswanted  
  989.     if (i == nodesetup[0].nodeswanted)
  990.       break;         // got them all
  991.  
  992.     //
  993.     // send out a broadcast packet every second
  994.     //
  995.     ppctimer (clock);
  996.     currsec = (clock[1] / (bus_clock>>2));
  997.     if (currsec != oldsec) {
  998.       oldsec = currsec;
  999.  
  1000.       printf (".");
  1001.       fflush (stdout);
  1002.  
  1003.       nodesetup[0].nodesfound = doomcom->numnodes;
  1004.       memcpy (&doomcom->data, &nodesetup[0], sizeof(setupdata_t));
  1005.       doomcom->remotenode = MAXNETNODES;
  1006.       doomcom->datalength = sizeof(setupdata_t);
  1007.       IPX_PacketSend ();     // send to all
  1008.     }
  1009.  
  1010.   } /* end for (;;) until all nodes have found all other nodes */
  1011.  
  1012. //
  1013. // count players
  1014. //
  1015.   total = 0;
  1016.   console = 0;
  1017.  
  1018.   for (i = 0; i < numnetnodes; i++) {
  1019.     if (nodesetup[i].drone)
  1020.       continue;
  1021.     total++;
  1022.     if (total > MAXPLAYERS)
  1023.       I_Error ("More than %i players specified!", MAXPLAYERS);
  1024.     if (M_CheckParm ("-reverseipx")) {
  1025.       if (memcmp (&IPX_nodeadr[i], &IPX_nodeadr[0], sizeof(IPX_nodeadr[0])) > 0)
  1026.         console++;
  1027.     } else {
  1028.       if (memcmp (&IPX_nodeadr[i], &IPX_nodeadr[0], sizeof(IPX_nodeadr[0])) < 0)
  1029.         console++;
  1030.     }
  1031.   }
  1032.  
  1033.   if (!total)
  1034.     I_Error ("No players specified for game!");
  1035.  
  1036.   doomcom->consoleplayer = console;
  1037.   doomcom->numplayers = total;
  1038.  
  1039.   printf ("Console is player %i of %i\n", console+1, total);
  1040. }
  1041.  
  1042. /**********************************************************************/
  1043. void IPX_InitNetwork (int p)
  1044. {
  1045.   int i, socket;
  1046.  
  1047. //
  1048. // get IPX function address
  1049. //
  1050.   if ((AMIPX_Library = (struct AMIPX_Library *)OpenLibrary
  1051.                                                  ("amipx.library",0L)) == NULL)
  1052.     I_Error ("Can't open amipx.library");
  1053.  
  1054. //
  1055. // allocate a socket for sending and receiving
  1056. //
  1057.   socket = 0x869b;
  1058.   i = M_CheckParm ("-socket");
  1059.   if (i && i < myargc - 1) {
  1060.     socket = atoi (myargv[i+1]);
  1061.   }
  1062.   IPX_socketid = IPX_OpenSocket (socket);
  1063.   printf ("Using IPX socket 0x%04x\n", IPX_socketid);
  1064.  
  1065.   AMIPX_GetLocalAddr ((BYTE *)&IPX_localadr);
  1066.   printf ("Local address is [%02x:%02x:%02x:%02x:%02x:%02x]\n",
  1067.           IPX_localadr.node[0], IPX_localadr.node[1], IPX_localadr.node[2],
  1068.           IPX_localadr.node[3], IPX_localadr.node[4], IPX_localadr.node[5]);
  1069.  
  1070. //
  1071. // set up several receiving ECBs
  1072. //
  1073.   memset (IPX_packets, 0, IPX_NUMPACKETS * sizeof(packet_t));
  1074.  
  1075.   for (i = 1; i < IPX_NUMPACKETS; i++) {
  1076.     IPX_packets[i].ecb.Socket = IPX_socketid;
  1077.     IPX_packets[i].ecb.FragCount = 2;
  1078.     IPX_packets[i].ecb.Fragment[0].FragData = (BYTE *)&IPX_packets[i].ipx;
  1079.     IPX_packets[i].ecb.Fragment[0].FragSize = sizeof(struct AMIPX_PacketHeader)
  1080.                                             + sizeof(long);
  1081.     IPX_packets[i].ecb.Fragment[1].FragData = (BYTE *)&IPX_packets[i].data;
  1082.     IPX_packets[i].ecb.Fragment[1].FragSize = sizeof(doomdata_t);
  1083.     IPX_ListenForPacket (&IPX_packets[i].ecb);
  1084.   }
  1085.  
  1086. //
  1087. // set up a sending ECB
  1088. //
  1089.   memset (&IPX_packets[0],0,sizeof(IPX_packets[0]));
  1090.  
  1091.   IPX_packets[0].ecb.Socket = IPX_socketid;
  1092.   IPX_packets[0].ecb.FragCount = 2;
  1093.   IPX_packets[0].ecb.Fragment[0].FragData = (BYTE *)&IPX_packets[0].ipx;
  1094.   IPX_packets[0].ecb.Fragment[1].FragData = (BYTE *)&doomcom->data;
  1095.   memcpy (IPX_packets[0].ipx.Dst.Network, IPX_localadr.network, 4);
  1096.   IPX_packets[0].ipx.Dst.Socket = IPX_socketid;
  1097.  
  1098.   /* why doesn't amipx.library fill in ipx.Src? */
  1099.   memcpy (&IPX_packets[0].ipx.Src, &IPX_localadr, 4 + 6);
  1100.   IPX_packets[0].ipx.Src.Socket = IPX_socketid;
  1101.  
  1102. // known local node at 0
  1103.   memcpy (IPX_nodeadr[0].node, IPX_localadr.node, 6);
  1104.  
  1105. // broadcast node at MAXNETNODES
  1106.   memset (IPX_nodeadr[MAXNETNODES].node, 0xff, 6);
  1107.  
  1108.   netsend = IPX_PacketSend;
  1109.   netget = IPX_PacketGet;
  1110.   netgame = true;
  1111.  
  1112.   // parse player number and host list
  1113.  
  1114.   IPX_LookForNodes (myargv[p+1][0] - '0');
  1115.  
  1116.   IPX_localtime = 0;
  1117.  
  1118.   doomcom->id = DOOMCOM_ID;
  1119. }
  1120.  
  1121. /**********************************************************************/
  1122. static void IPX_Shutdown (void)
  1123. {
  1124.   if (IPX_socketid != 0) {
  1125.     printf ("IPX_Shutdown: Closing socket and library\n");
  1126.     AMIPX_CloseSocket (IPX_socketid);
  1127.     IPX_socketid = 0;
  1128.   }
  1129.   if (AMIPX_Library != NULL) {
  1130.     CloseLibrary ((struct Library *)AMIPX_Library);
  1131.     AMIPX_Library = NULL;
  1132.   }
  1133. }
  1134.  
  1135. /**********************************************************************/
  1136.  
  1137. #endif  /* IPX */
  1138.  
  1139. /**********************************************************************/
  1140. /**********************************************************************/
  1141. //
  1142. // I_InitNetwork
  1143. //
  1144. void I_InitNetwork (void)
  1145. {
  1146.   int i;
  1147.   int p;
  1148.  
  1149.   doomcom = malloc (sizeof (*doomcom) );
  1150.   memset (doomcom, 0, sizeof(*doomcom) );
  1151.  
  1152.   // set up for network
  1153.   i = M_CheckParm ("-dup");
  1154.   if (i && i < myargc - 1) {
  1155.     doomcom->ticdup = myargv[i+1][0]-'0';
  1156.     if (doomcom->ticdup < 1)
  1157.       doomcom->ticdup = 1;
  1158.     if (doomcom->ticdup > 9)
  1159.       doomcom->ticdup = 9;
  1160.   } else
  1161.     doomcom-> ticdup = 1;
  1162.  
  1163.   if (M_CheckParm ("-extratic"))
  1164.     doomcom-> extratics = 1;
  1165.   else
  1166.     doomcom-> extratics = 0;
  1167.  
  1168.   p = M_CheckParm ("-port");
  1169.   if (p && p < myargc - 1) {
  1170.     IP_DOOMPORT = atoi (myargv[p+1]);
  1171.     printf ("using alternate port %i\n",IP_DOOMPORT);
  1172.   }
  1173.  
  1174.   // parse network game options,
  1175.   //  -net <consoleplayer> <host> <host> ...
  1176.   if ((i = M_CheckParm ("-net")) != 0) {
  1177.  
  1178.     IP_InitNetwork (i);
  1179.  
  1180.   } else if ((i = M_CheckParm ("-netserial")) != 0) {
  1181.  
  1182.     SER_InitNetwork (i);
  1183.  
  1184. #ifdef AMIPX
  1185.  
  1186.   } else if ((i = M_CheckParm ("-netipx")) != 0) {
  1187.  
  1188.     IPX_InitNetwork (i);
  1189.  
  1190. #endif
  1191.  
  1192.   } else {
  1193.  
  1194.     // single player game
  1195.     netgame = false;
  1196.     doomcom->id = DOOMCOM_ID;
  1197.     doomcom->numplayers = doomcom->numnodes = 1;
  1198.     doomcom->deathmatch = false;
  1199.     doomcom->consoleplayer = 0;
  1200.  
  1201.   }
  1202. }
  1203.  
  1204.  
  1205. /**********************************************************************/
  1206. void I_NetCmd (void)
  1207. {
  1208.   if (doomcom->command == CMD_SEND) {
  1209. #ifdef AMIPX
  1210.     IPX_localtime++;
  1211. #endif
  1212.     netsend ();
  1213.   } else if (doomcom->command == CMD_GET) {
  1214.     netget ();
  1215.   } else
  1216.     I_Error ("Bad net cmd: %i\n",doomcom->command);
  1217. }
  1218.  
  1219. /**********************************************************************/
  1220. void _STDcleanup_net (void)
  1221. {
  1222.   IP_Shutdown ();
  1223.   SER_Shutdown ();
  1224. #ifdef AMIPX
  1225.   IPX_Shutdown ();
  1226. #endif
  1227. }
  1228.  
  1229. /**********************************************************************/
  1230.